package com.allwees.support.fileservice.service.impl;

import com.aliyun.oss.ClientConfiguration;
import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClient;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.common.auth.DefaultCredentialProvider;
import com.aliyun.oss.common.utils.IOUtils;
import com.aliyun.oss.model.OSSObject;
import com.aliyun.oss.model.PutObjectResult;
import com.allwees.core.common.util.DateUtil;
import com.allwees.support.fileservice.FileException;
import com.allwees.support.fileservice.config.AliOssConfig;
import com.allwees.support.fileservice.model.FileEntity;
import com.allwees.support.fileservice.model.FileMetadata;
import com.allwees.support.fileservice.model.PutFileResult;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.Date;
import java.util.concurrent.Executor;


/**
 * FileService的阿里云实现
 *
 * @author yangylsky
 */
@Service
@Lazy
@Slf4j
public class AliossFileService extends BaseFileService implements InitializingBean {
	private static OSS client;

	@Autowired
	private AliOssConfig aliOssConfig;

	@Resource(name = "taskExecutor")
	private Executor taskExecutor;

	@Override
	public void afterPropertiesSet() {
		init();
	}

	private void init() {
		AliOssConfig alioss = aliOssConfig;
		if(alioss.isEnable()) {
			try {
				client = new OSSClient(alioss.getEndpoint(),new DefaultCredentialProvider(alioss.getAccessKeyId(), alioss.getAccessKeySecret()),new ClientConfiguration());
				log.info("阿里云OSS初始化成功!");
				taskExecutor.execute(this::checkBuckets);
			} catch(Throwable t) {
				log.error("阿里云OSS客户端创建失败", t);
			}
		}
	}

	@Async
	public void checkBuckets() {
		String[] buckets = StringUtils.join(new String[] {config.getSysBuckets(), config.getBsBuckets(),
				config.getUserBucket(), config.getTempBucket()}, ",").split(",");
		for(String bucket : buckets) {
			if(StringUtils.isNotBlank(bucket) && !isBucketExist(bucket.trim())) {
				createBucket(bucket.trim());
			}
		}
	}

	@Override
	public String getType() {
		return "alioss";
	}

	@Override
	public String getAccessPrefix() {
		return aliOssConfig.getAccessPrefix();
	}

	@Override
	public String genFileKey(String key) {
		String year = DateUtil.formatDate(new Date(), "yyyy");
		return year + "/" + key;
	}

	@Override
	public void createBucket(String bucket) {
		try {
			client.createBucket(bucket);
			log.info("创建Bucket[{}]成功", bucket);
		} catch(OSSException | ClientException e) {
			log.error("创建Bucket[" + bucket + "]失败", e);
			throw new FileException(e);
		}
	}

	@Override
	public boolean isBucketExist(String bucket) {
		try {
			return client.doesBucketExist(bucket);
		} catch(OSSException | ClientException e) {
			throw new FileException(e);
		}
	}

	@Override
	public PutFileResult putFile(String bucket, String key, InputStream input, long length) {
		// 创建上传File的Metadata
		FileMetadata meta = new FileMetadata();

		// 必须设置ContentLength
		meta.setContentLength(length);

		try {
			PutObjectResult putResult = client.putObject(bucket, convertKey(key), input, meta);
			return new PutFileResult(putResult);
		} catch(OSSException | ClientException e) {
			log.error("发送文件失败[" + bucket + ":" + key + "]", e);
			throw new FileException(e);
		} finally {
			IOUtils.safeClose(input);
		}
	}

	@Override
	public PutFileResult putFile(String bucket, String key, byte[] content) {
		InputStream input = new ByteArrayInputStream(content);
		return putFile(bucket, key, input, content.length);
	}

	@Override
	public FileEntity getFileEntity(String bucket, String key) {
		try {
			OSSObject ossObject = client.getObject(bucket, convertKey(key));
			return new FileEntity(ossObject);
		} catch(OSSException | ClientException e) {
			log.error("获取文件失败[" + bucket + ":" + key + "]", e);
			throw new FileException(e);
		}
	}

	private String convertKey(String key) {
		return StringUtils.replaceChars(key, "\\", "/");
	}
}
